package com.example.forum.utils;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * 功能描述:
 *
 * @author Lenovo
 * @date 2025/2/15
 */
@Slf4j
@Configuration
public class RedisUtil {

    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * 设置值
     *
     * @param key
     * @param value
     * @return
     */
    public boolean set(String key, String value) {
        try {
            redisTemplate.opsForValue().set(key, value);
            return true;
        } catch (Exception e) {
            log.error("RedisUtil error,set({},{}): ", key, value, e);
            return false;
        }
    }

    /**
     * 设置值并设置过期时间
     *
     * @param key
     * @param value
     * @param time
     * @return
     */
    public boolean set(String key, String value, Long time) {
        try {
            redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
            return true;
        } catch (Exception e) {
            log.error("RedisUtil error,set({},{},{}s): ", key, value, time, e);
            return false;
        }
    }

    /**
     * 获取值
     *
     * @param key
     * @return
     */
    public String get(String key) {
        try {
            String s = redisTemplate.opsForValue().get(key);
            return StringUtils.hasText(key) ? s : null;
        } catch (Exception e) {
            log.error("RedisUtil error,get({}): ", key, e);
            return null;
        }
    }

    /**
     * 删除key
     *
     * @param key
     * @return
     */
    public boolean delete(String... key) {
        try {
            if (key != null && key.length > 0) {
                if (key.length == 1) {
                    redisTemplate.delete(key[0]);
                } else {
                    redisTemplate.delete((Collection<String>) CollectionUtils.arrayToList(key));
                }
            }
            return true;
        } catch (Exception e) {
            log.error("RedisUtil error,delete({}): ", key, e);
            return false;
        }
    }

    public boolean hasKey(String key) {
        try {
            Boolean b = redisTemplate.hasKey(key);
            return StringUtils.hasText(key) ? b : false;
        } catch (Exception e) {
            log.error("RedisUtil error,hasKey({}): ", key, e);
            return false;
        }
    }

    /**
     * 添加有序集合元素
     */
    public boolean zAdd(String key, String value, double score) {
        try {
            return redisTemplate.opsForZSet().add(key, value, score);
        } catch (Exception e) {
            log.error("RedisUtil error,zAdd({},{},{}): ", key, value, score, e);
            return false;
        }
    }

    /**
     * 获取有序集合中指定范围的元素（按分数从高到低）
     */
    public Set<String> zReverseRange(String key, long start, long end) {
        try {
            return redisTemplate.opsForZSet().reverseRange(key, start, end);
        } catch (Exception e) {
            log.error("RedisUtil error,zReverseRange({},{},{}): ", key, start, end, e);
            return null;
        }
    }

    /**
     * 获取有序集合中指定分数范围的元素
     */
    public Set<String> zRangeByScore(String key, double min, double max) {
        try {
            return redisTemplate.opsForZSet().rangeByScore(key, min, max);
        } catch (Exception e) {
            log.error("RedisUtil error,zRangeByScore({},{},{}): ", key, min, max, e);
            return null;
        }
    }

    /**
     * 获取有序集合大小
     */
    public Long zSize(String key) {
        try {
            return redisTemplate.opsForZSet().size(key);
        } catch (Exception e) {
            log.error("RedisUtil error,zSize({}): ", key, e);
            return null;
        }
    }

    /**
     * 从有序集合中移除元素
     */
    public Long zRemove(String key, Object... values) {
        try {
            return redisTemplate.opsForZSet().remove(key, values);
        } catch (Exception e) {
            log.error("RedisUtil error,zRemove({},{}): ", key, Arrays.toString(values), e);
            return null;
        }
    }

    /**
     * 获取有序集合中指定范围的元素（按分数从低到高）
     */
    public Set<String> zRange(String key, long start, long end) {
        try {
            return redisTemplate.opsForZSet().range(key, start, end);
        } catch (Exception e) {
            log.error("RedisUtil error,zRange({},{},{}): ", key, start, end, e);
            return null;
        }
    }

    /**
     * 存储Hash
     */
    public void hmset(String key, Map<String, String> map) {
        try {
            redisTemplate.opsForHash().putAll(key, map);
        } catch (Exception e) {
            log.error("RedisUtil error,hmset({},{}): ", key, map, e);
        }
    }

    /**
     * 获取Hash所有字段
     */
    public Map<Object, Object> hmget(String key) {
        try {
            return redisTemplate.opsForHash().entries(key);
        } catch (Exception e) {
            log.error("RedisUtil error,hmget({}): ", key, e);
            return null;
        }
    }

    /**
     * 设置过期时间
     */
    public boolean expire(String key, long time) {
        try {
            return Boolean.TRUE.equals(redisTemplate.expire(key, time, TimeUnit.SECONDS));
        } catch (Exception e) {
            log.error("RedisUtil error,expire({},{}): ", key, time, e);
            return false;
        }
    }

    /**
     * 删除key
     */
    public void del(String key) {
        try {
            redisTemplate.delete(key);
        } catch (Exception e) {
            log.error("RedisUtil error,del({}): ", key, e);
        }
    }

    /**
     * 递增操作
     * @param key 键
     * @param delta 递增因子
     * @return 递增后的值
     */
    public Long increment(String key, long delta) {
        try {
            return redisTemplate.opsForValue().increment(key, delta);
        } catch (Exception e) {
            log.error("RedisUtil error,increment({},{}): ", key, delta, e);
            return null;
        }
    }

    /**
     * 滑动窗口限流
     * @param key 限流key
     * @param windowSize 窗口大小(秒)
     * @param limit 限制次数
     * @return true:允许访问 false:被限流
     */
    public boolean isActionAllowed(String key, int windowSize, int limit) {
        try {
            long currentTime = System.currentTimeMillis();
            long windowStart = currentTime - windowSize * 1000; // 窗口起始时间
            
            // 移除窗口之前的数据
            redisTemplate.opsForZSet().removeRangeByScore(key, 0, windowStart);
            
            // 获取当前窗口的行为次数
            Long count = redisTemplate.opsForZSet().zCard(key);
            if (count != null && count >= limit) {
                return false;
            }
            
            // 记录本次行为
            redisTemplate.opsForZSet().add(key, String.valueOf(currentTime), currentTime);
            
            // 设置key过期时间为窗口大小的2倍,（即使后来没有请求，也会自动清理）防止冷数据占用内存
            redisTemplate.expire(key, windowSize * 2L, TimeUnit.SECONDS);
            
            return true;
        } catch (Exception e) {
            log.error("RedisUtil error, isActionAllowed({},{},{}): ", key, windowSize, limit, e);
            return false;
        }
    }
}
